#!/usr/bin/env perl
#
# Copyright (c) 2013 Jeffrey M. Squyres.  All rights reserved.
# $COPYRIGHT$
#

use strict;

use Data::Dumper;
use Getopt::Long;
use POSIX;

my $data_by_name;
my @data_by_time;

###########################################################################

my $num_days_arg = 3;
my $infile_arg = "mdns-device-data.txt";
my $outfile_arg;
my $help_arg;

&Getopt::Long::Configure("bundling");
my $ok = Getopt::Long::GetOptions("file|f=s" => \$infile_arg,
                                  "outfile|o=s" => \$outfile_arg,
                                  "days|d=i" => \$num_days_arg,
                                  "help|h" => \$help_arg
                                  );

if (!$ok || $help_arg) {
    print "Options:
--file | -f filename   Input filename
--outfile | -o outfile Output filename
--days | -d days       Graph the last <days> days (all if unspecified)
--help | -h            This help message\n";
    exit(!$ok);
}


###########################################################################
# Read in the file

if (!defined($outfile_arg)) {
    $outfile_arg = $infile_arg;
    $outfile_arg =~ s/\.(txt|out|data)$//;
    $outfile_arg .= ".pdf";
}

# Default to showing the last 3 days
# mktime (sec, min, hour, mday, mon, year, wday, yday, isdst)
my $lower_bound = 0;
$lower_bound = time() - $num_days_arg * 24 * 60 * 60
    if ($num_days_arg > 0);

my $num_items = 0;
my ($min_x, $max_x);
print "Reading from $infile_arg...\n";
open(IN, $infile_arg) || die "Can't open $infile_arg file";
while(<IN>) {
    my @fields = split(/,/);

    my $ctime = $fields[0];
    my $timestamp = $fields[1];
    my $name = $fields[2];
    chomp($name);

    print "Timestamp: " . localtime($timestamp) . " / lower bound: " . localtime($lower_bound) . "\n";
    next
        if (defined($lower_bound) && $timestamp < $lower_bound);

    # The first timestamp we get is the min_x
    $min_x = $timestamp
        if (!defined($min_x));
    # Keep a rolling value of the max_x
    $max_x = $timestamp;

    push(@{$data_by_name->{$name}}, {
        timestamp => $timestamp,
        ctime => $ctime
         });

    push(@data_by_time, {
        name => $name,
        timestamp => $timestamp,
        ctime => $ctime
         });
    ++$num_items;
}
close(IN);
print "Read in $num_items items\n";

if (0 == $num_items) {
    print "Nothing to do!\n";
    exit(0);
}

###########################################################################
# Plot it

# Fix the Y values: one for each device
my $y = 1;
my @yvalues;
foreach my $name (sort(keys(%{$data_by_name}))) {
    push(@yvalues, {
        yval => $y,
        name => $name,
         });
    ++$y;
}
my $max_y = $y;

# Write out data files; one for each device
foreach my $y (@yvalues) {
    my $yval = $y->{yval};
    my $name = $y->{name};

    my $file = "gnuplot-$yval.dat";
    unlink($file);
    open(OUT, ">$file") || die "Can't write to $file";
    foreach my $val (@{$data_by_name->{$name}}) {
        print OUT $val->{timestamp} . " " . $yval . "\n";
    }
    close(OUT);
}

# Make the sequence of gnuplot commands
my $str = "set terminal pdf
set title \"MDNS devices\"
set xlabel \"Timestamps\"
set ylabel \"Device\"
set output \"$outfile_arg\"
set nokey\n";

# Make the y range start at 0 (since our first device is at y=1)
# and end at (1+largest_device_number)
$str .= "set yrange [0:$max_y]\n";

# Set the y labels
$str .= "set ytics nomirror (\"\" 0";
foreach my $y (@yvalues) {
    my $yval = $y->{yval};
    my $name = $y->{name};

    $str .= ", \"$name\" $yval";
}
$str .= ", \"\" $max_y)\n";

# Make some x axis labels.
sub label {
    my $timestamp = shift;
    my $lt = localtime($timestamp);
    $lt =~ s/(\d\d:\d\d):\d\d \d\d\d\d/\1/;
    return $lt;
}
my $range_x = $max_x - $min_x;
my $num_labels = 9;
my $incr = $range_x / ($num_labels - 1);
my $i = 0;
my $x = $min_x;
my $first = 1;
$str .= "set xtics nomirror rotate by -90 (";
while ($i < $num_labels) {
    $str .= ", "
        if (!$first);
    $first = 0;

    $str .= "\"" . label($x) . "\" $x";
    $x += $incr;
    ++$i;
}
$str .= ")\n";

# Commands for the plot lines
$str .= "plot ";
my $first = 1;
foreach my $y (@yvalues) {
    my $yval = $y->{yval};
    my $name = $y->{name};

    $str .= ", "
        if (!$first);
    $first = 0;

    $str .= "\"gnuplot-$yval.dat\" using 1:2 title \"$name\"";
}
$str .= "
exit\n";

# Run gnuplot and feed it our commands
open(G, "|gnuplot") || die "Can't open gnuplot";
print G $str;
close(G);
print "Plotted output to $outfile_arg\n";

# Remove the temp gnuplot files
foreach my $y (@yvalues) {
    my $yval = $y->{yval};
    my $file = "gnuplot-$yval.dat";
    unlink($file);
}

# All done!
exit(0);
